{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "theta1.shape: (25, 401)\n",
      "theta2.shape: (10, 26)\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import scipy.io as scio\n",
    "\n",
    "data = scio.loadmat('data_sets/ex3data1')\n",
    "weights = scio.loadmat('data_sets/ex3weights')\n",
    "x = data['X']\n",
    "y = data['y']\n",
    "theta1 = weights['Theta1'] # Theta1 has size 25 x 401\n",
    "theta2 = weights['Theta2'] # Theta2 has size 10 x 26\n",
    "\n",
    "print('theta1.shape:', theta1.shape)\n",
    "print('theta2.shape:', theta2.shape)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "'''Model representation'''\n",
    "# activation function\n",
    "def g(z):\n",
    "    return 1/(1 + np.exp(-z))\n",
    "\n",
    "# add one col to every layer besides Output layer as one bias unit\n",
    "def plus_col(x):\n",
    "    return np.column_stack((np.ones(x.shape[0]), x))\n",
    "\n",
    "# feedforward propagation function\n",
    "def forward_pro(x, theta1, theta2):\n",
    "    b1 = x # (5000, 400)\n",
    "    for i in range(1, 3): # the range denotes the number of layers\n",
    "        locals()['a' + str(i)] = plus_col(locals()['b' + str(i)])\n",
    "        locals()['z' + str(i + 1)] = locals()['a' + str(i)] @ locals()['theta' + str(i)].T\n",
    "        locals()['b' + str(i + 1)] = g(locals()['z' + str(i + 1)])\n",
    "    return locals()['b3'] # the size of b3 is (5000, 10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "accuracy = 97.52%\n"
     ]
    }
   ],
   "source": [
    "'''Feedforward Propagation and Prediction'''\n",
    "# predict the value of y based on the maximum probability of h_x\n",
    "def predict(prob):\n",
    "    y_predict = np.zeros((prob.shape[0], 1))\n",
    "    for i in range(prob.shape[0]):\n",
    "        y_predict[i] = np.argmax(prob[i, :]) + 1\n",
    "    return y_predict\n",
    "\n",
    "def accuracy(y_predict, y = y):\n",
    "    m = y.size\n",
    "    count = 0\n",
    "    for i in range(m):\n",
    "        if y_predict[i] == y[i]:\n",
    "            count += 1\n",
    "    return count / m\n",
    "\n",
    "prob = forward_pro(x, theta1, theta2)\n",
    "y_predict = predict(prob)\n",
    "print('accuracy = {0}%'.format(accuracy(y_predict) * 100))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
